package tf2pickup;

import java.io.FileNotFoundException;
import java.io.FileReader;

import java.io.IOException;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.esotericsoftware.yamlbeans.YamlException;
import com.esotericsoftware.yamlbeans.YamlReader;

import java.io.File;
import org.pircbotx.*;
import org.pircbotx.exception.IrcException;

import tf2pickup.exceptions.FaultyConfigurationFile;
import tf2pickup.listeners.AddPlayer;
import tf2pickup.listeners.OnConnect;
import tf2pickup.listeners.OnNickChange;
import tf2pickup.listeners.PrintPlainText;
import tf2pickup.listeners.PrintStatus;
import tf2pickup.listeners.RemovePlayer;
import tf2pickup.listeners.VoteMap;

/**
 * The Bot object represents one pickup-bot in the IRC. It listens to the
 * various commands and is able to be configured by an configuration-file.
 * @author Philipp Preß
 */
public class Bot {
    
    private static File configFile;
    private static PircBotX bot;
    private static Players players;
    private static HashMap<String, Integer> maps;
    private static ArrayList<GameServer> servers;

    /**
     * Bot gets instantiated and will load his configuration. The
     * configuration-file will be checked for errors. The bot then attempts to 
     * connect to the specified irc-server and irc-channel, preparing itself to 
     * organize pickups
     * @param First argument has to be the path to the
     * configuration-file.
     * @throws FaultyConfigurationFile if a necessary value / property is 
     * missing in the configuration file.
     * @throws IllegalArgumentException if arguments are invalid.
     */
    public static void main(String[] args) throws FaultyConfigurationFile {
        try {

            //Check if program was started with parameters.
            if (args.length < 1) {
                throw new IllegalArgumentException("No arguments passed. First "
                        + "argument has to be the path to the "
                        + "configuration-file.");
            }
            
            configFile = new File(args[0]);

            //Check if passed path is an file that actually exists and is readable
            if (!(configFile.exists() && configFile.isFile())) {
                throw new IllegalArgumentException("Configuration-file does"
                        + " not exist or is not an file");
            }
            if(!(configFile.canRead())){
                throw new IllegalArgumentException("Cannot read configuration-file.");
            }
            
            bot = new PircBotX();
            players = new Players(12);
            maps = new HashMap<String, Integer>();

            //Attempt to read the config-file
            YamlReader reader = new YamlReader(new FileReader(configFile));
            reader.getConfig().setPropertyElementType(Config.class, "servers", GameServer.class);
            Config cfg = reader.read(Config.class);

            //Check configuration for errors / missing entries
            cfg.checkConfig();

            //Add servers from configuration-file
            servers = cfg.servers;

            //Add maps from the configuration-file
            //(starting with 0 votes for each map ofc)
            for (String map : cfg.maps) {
                maps.put(map, 0);
            }

            //Add Listeners
            bot.getListenerManager().addListener(new AddPlayer(players, maps, servers));
            bot.getListenerManager().addListener(new OnNickChange(players, cfg));
            bot.getListenerManager().addListener(new OnConnect(cfg));
            bot.getListenerManager().addListener(new PrintPlainText(cfg));
            bot.getListenerManager().addListener(new PrintStatus(players, maps));
            bot.getListenerManager().addListener(new RemovePlayer(players, maps, cfg));
            bot.getListenerManager().addListener(new VoteMap(maps, players));

            //Connect to the specified irc server
            bot.setVerbose(cfg.botVerbose);
            bot.setAutoNickChange(cfg.botAutoNickChange);
            bot.setName(cfg.ircNickname);
            bot.connect(cfg.ircServer, cfg.ircPort);
        } catch (YamlException ex) {
            Logger.getLogger(Bot.class.getName()).log(Level.SEVERE, "Couldn't "
                    + "parse configuration file \"config.yaml\".", ex);
        } catch (FileNotFoundException ex) {
            Logger.getLogger(Bot.class.getName()).log(Level.SEVERE, "Couldn't "
                    + "find configuration file \"config.yaml\".", ex);
        } catch (IOException ex) {
            Logger.getLogger(Bot.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IrcException ex) {
            Logger.getLogger(Bot.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
